`timescale 1ns/100ps
`default_nettype none

/* NOTE:
* - 根据行号和分区ID计算SDRAM写入地址
*/

module rgb_row_addr_decoder (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,

    input  wire [10:0]  I_cfg_win_col_num,  // 带载列数（宽度）
    input  wire [10:0]  I_cfg_win_row_num,      // 带载行数（高度）
    
    // row info
    output wire         O_row_info_req,
    output wire [9:0]   O_row_info_index,
    input  wire [15:0]  I_row_info_data,
    input  wire         I_row_info_end,
    
    // addr decoder
    input  wire         I_decode_req,     // 行地址译码请求
    input  wire [1:0]   I_decode_buf_sel, // SDRAM按帧分块选择
    input  wire [9:0]   I_decode_row,     // 行号
    input  wire [3:0]   I_decode_sector,  // 分区号
    output wire         O_decode_done,    // 译码完成
    output wire [20:0]  O_decode_addr     // 译码结果
);
//------------------------Parameter----------------------
// fsm
localparam [2:0]
    IDLE = 0,
    DIV  = 1,
    CALC = 2,
    OVER = 3;

// box direction
localparam [1:0]
    LANDSCAPE = 0, // 横向
    PORTRAIT0 = 1, // 纵向，第一个端口在左侧
    PORTRAIT1 = 2; // 纵向，第一个端口在右侧

//------------------------Local signal-------------------
// fsm
reg  [2:0]  state;
reg  [2:0]  next;


// decode
reg         decode_done;
reg  [1:0]  frame_id;
reg  [7:0]  col_addr;
reg  [10:0] row_addr;
reg  [1:0]  bank_addr;
reg  [3:0]  sector_id;
reg  [1:0]  col_map_sel;
reg  [9:0]  row_info_data;

//------------------------Body---------------------------
//{{{+++++++++++++++++++++fsm++++++++++++++++++++++++++++
// state
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        state <= IDLE;
    else
        state <= next;
end

// next
always @(*) begin
    case (state)
        IDLE: begin
            if (I_decode_req)
                next = DIV;
            else
                next = IDLE;
        end

        DIV: begin
            if (I_row_info_end)
                next = CALC;
            else 
                next = IDLE;
        end

        CALC: begin
            next = OVER;
        end

        OVER: begin
            next = IDLE;
        end

        default: begin
            next = IDLE;
        end
    endcase
end


reg  [10:0]  cfg_win_col_num;  // 带载列数（宽度）
reg  [10:0]  cfg_win_row_num;     

always@(posedge I_sclk)begin
    cfg_win_col_num <= I_cfg_win_col_num + 8'd63;
    cfg_win_row_num <= I_cfg_win_row_num + 8'd63;
end

assign O_row_info_req = I_decode_req;
assign O_row_info_index = I_decode_row;

//{{{+++++++++++++++++++++decode+++++++++++++++++++++++++
assign O_decode_done = decode_done;
assign O_decode_addr = {row_addr, bank_addr,  col_addr};

// decode_done
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)
        decode_done <= 1'b0;
    else if (state == OVER)
        decode_done <= 1'b1;
    else
        decode_done <= 1'b0;
end

// frame_id
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        frame_id <= 1'b0;
    else if (I_decode_req)
        frame_id <= I_decode_buf_sel;
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        row_info_data <= 1'b0;
    else if (I_row_info_end)
        row_info_data <= I_row_info_data[9:0];
end

always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        col_map_sel <= 1'b0;
    else if (I_row_info_end)
        col_map_sel <= I_row_info_data[15:14];
end

// row_addr
always @(posedge I_sclk or negedge I_rst_n) begin
    if (!I_rst_n)begin
        row_addr <= 1'b0;
        bank_addr <= 1'b0;
        col_addr <= 1'b0;
    end
    else if (state == OVER)begin
        row_addr[10:8] <= {2'b00, frame_id[0]};
        row_addr[7:2]  <= row_info_data[9:6] * cfg_win_col_num[9:6];
        row_addr[1:0]  <= 'b0 ;
        bank_addr <= { 2'b0 };
        col_addr <= { row_info_data[5:0] , 2'b0 };
   end
end

//}}}++++++++++++++++++++++++++++++++++++++++++++++++++++

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
